
//
// 120930 - AH - Created.
// 121010 - AH - performTests now accepts world object since
//               changed worlds may be created not by tests but factory and
//               tests paths may be run over several 'worlds'.
// 121110a- AH - Made performTests(TestContext tc, Object) only public method
//               to perform tests and handles that second argument can be a 
//               WorldHandler.
// 121110b- AH - Added some tc logging done from here about which test being
//               performed and if performed OK or not.
// 121111 - AH - Reset tests in a path before performing.
// 121113 - AH - Changed signature to run test from one refered to in 121110a
//               to public void performTests(TestContext, TestFactory, String),
//               needed to be able to create world for each path.
//

package org.japril.jhut.framework;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *   Paths of a forest of 
 *   {@link JhutTest}s.
 * </p>
 * @author Arne Halvorsen (AH)
 */
public final class TreeTestPaths
{
  private final List<JhutTest[]> m_paths=new ArrayList<JhutTest[]>();
  
  private static final class LeafCollectorVisitor implements TestTreeVisitor
  {
    final List<JhutTest> leafs=new ArrayList<JhutTest>();
    
    LeafCollectorVisitor(){}

    @Override
    public boolean visit(JhutTest visited)
    { 
      if (visited.isLeaf()) leafs.add(visited);
      return true;
    }
    
  }
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param forest Roots in the forest.
   */
  public TreeTestPaths(List<JhutTest> forest)
  {
    if (forest==null)
    {
      throw new NullPointerException("root");
    }
    
    LeafCollectorVisitor lcv=new LeafCollectorVisitor();
    int n=forest.size();
    for (int i=0; i<n; i++)
    {
      JhutTest curr=forest.get(i);
      if (curr==null)
      {
        throw new IllegalArgumentException("forest["+i+"]");
      }
      
      curr.dfs(lcv);
    }
    
    for (JhutTest curr : lcv.leafs) m_paths.add(curr.getPath());  
  }
  
  /**
   * <p>
   *   Performs tests.
   * </p>
   * @param tc    Context tests run in.
   * @param world World object to run tests over, allowed to be {@code null}.
   * @param wh    {@link WorldHandler} with 
   *              {@link WorldValidator}s. May be {@code null} and is not
   *              required to have validators for all tests.
   */
  public void performTests(TestContext tc, TestFactory factory, String wname)
  { 
    int n=m_paths.size();
    for (int i=0; i<n; i++)
    {
      JhutTest[] path=m_paths.get(i);
      if (path.length>0)
      {
        Object world=(wname==null) ? null : factory.createWorld(wname);
        if (world!=null) path[0].setWorld(world);
        performTests(tc, path, world);
      }
    }
  }
  
  /**
   * <p>
   *   Performs tests of a path.
   * </p>
   * @param tc   Context tests run in.
   * @param path Path.
   * @param w    World object or a
   *             {@link WorldHandler} object, may be {@code null}.
   */
  private static void performTests(TestContext tc, JhutTest[] path, Object w)
  {
    reset(path);
    
    WorldHandler wh=(w instanceof WorldHandler) ? (WorldHandler)w : null;
    
    tc.testStarts(path);
    
    int n=path.length;
    for (int i=0; i<n; i++)
    {
      JhutTest curr=path[i];
      
      tc.testStart(curr);
      
      curr.performTest(tc);
      
      if (!curr.performed()) 
      {
        tc.log("test: "+curr.getName()+" did not perform");
        return;
      }
      else
      {
        tc.log("test: "+curr.getName()+" did perform, proceeds");
        tc.testEnd(curr);
      }
      
      if (wh!=null)
      {
        String name=curr.getName();
        WorldValidator wv=wh.getValidator(name);
        if (wh!=null)
        {
          wv.validate(wh.getWorld());
        }
      }
    }
  }
  
  private static final void reset(JhutTest[] path)
  { 
    for (JhutTest t : path) t.reset();
  }
  
}
